﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Vaffanculo.Model.Entities;
using Vaffanculo.Data.Implements;
using System.Data.Entity;
using Vaffanculo.Data.Interfaces;

namespace Vaffanculo.Data.Tests
{
    /// <summary>
    /// Tests for infrastructure independent data access to the data model or database
    /// </summary>
    [TestClass]
    public class RepositoryTest
    {
        public RepositoryTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        /// <summary>
        ///Test for data persistent infrastructure 
        ///Case: Add Project only repository
        ///Should be save data for project entity
        ///</summary>
        [TestMethod]
        public void SaveProjectOnlyRepositoryTest()
        {
            int oldCount = 0;
            int currentCount = 0;

            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();

            IDbContext context = new DbContextAdap(contextVaffanculo);
            IUnitOfWork uow = new UnitOfWork(context);

            // Define repository for Project
            Repository<Project> projectRepository = new Repository<Project>(uow);

            oldCount = projectRepository.GetCount();

            // Create Object type Project
            Project project = new Project()
            {
                ProjectId = 11,
                Code = "x_only_repository",
                CreationDate = DateTime.Now,
                DatabaseIp = "ip_only_repository",
                DatabaseName = "dbname_only_repository",
                DatabasePassword = "pwd_only_repository",
                DatabaseType = "type_only_repository",
                DatabaseUser = "user_only_repository",
                Description = "description_only_repository",
                ModifyDate = DateTime.Now,
                Name = "name_only_repository",
                Source = "source_only_repository"
            };
            // Added project
            projectRepository.Add(project);
            
            currentCount = projectRepository.GetCount();
            // Save Changes
            //uow.Commit();
            currentCount = projectRepository.GetCount();

            // Dispose context
            uow.GetIDbContext().Dispose();

            Console.WriteLine("Add Repository: old count = {0} | post commit count = {1} ", oldCount, currentCount);

            Assert.AreEqual(oldCount, currentCount);
        }

        /// <summary>
        ///Test for data persistent infrastructure 
        ///Case: Add Project in database with commit
        ///</summary>
        [TestMethod]
        public void SaveProjectTest()
        {
            int oldCount = -1;
            int postCommitCount = -1;

            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();

            IDbContext context = new DbContextAdap(contextVaffanculo);
            IUnitOfWork uow = new UnitOfWork(context);

            // Define repository for Project
            Repository<Project> projectRepository = new Repository<Project>(uow);

            oldCount = projectRepository.GetCount();

            // Create Object type Project
            Project project = new Project()
            {
                ProjectId = 11,
                Code = "x",
                CreationDate = DateTime.Now,
                DatabaseIp = "ip",
                DatabaseName = "dbname",
                DatabasePassword = "pwd",
                DatabaseType = "type",
                DatabaseUser = "user",
                Description = "description",
                ModifyDate = DateTime.Now,
                Name = "name",
                Source = "source"
            };
            // Added project
            projectRepository.Add(project);

            // Save Changes
            uow.Commit();
            postCommitCount = projectRepository.GetCount();

            // Dispose context
            uow.GetIDbContext().Dispose();

            Console.WriteLine("Add: old count = {0} | post commit count = {1} ", oldCount, postCommitCount);
            if (oldCount == -1)
            {
                Assert.AreNotEqual(oldCount, -1);
            }
            else
            {
                Assert.AreEqual(oldCount + 1, postCommitCount);
            }
        }

        /// <summary>
        ///Test for delete data
        ///Case: Delete Project in database with commit
        /// </summary>
        [TestMethod]
        public void DeleteProjectTest()
        {
            int oldCount = -1;
            int postCommitCount = -1;

            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();

            IDbContext context = new DbContextAdap(contextVaffanculo);
            IUnitOfWork uow = new UnitOfWork(context);

            // Define repository for Project
            Repository<Project> projectRepository = new Repository<Project>(uow);

            oldCount = projectRepository.GetCount();
            Project p = projectRepository.GetAll().ToList().Last();

            // Delete object
            projectRepository.Delete(p);

            uow.Commit();
            postCommitCount = projectRepository.GetCount();

            // Dispose context
            uow.GetIDbContext().Dispose();

            Console.WriteLine("Delete: old count = {0} | post commit count = {1} ",oldCount, postCommitCount);
            
            Assert.AreEqual(oldCount - 1, postCommitCount);
        }

        /// <summary>
        /// Test DeleteByFilter
        /// </summary>
        [TestMethod]
        public void DeleteByFilterTest()
        {
            int oldCount = -1;
            int postCommitCount = -1;

            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();

            IDbContext context = new DbContextAdap(contextVaffanculo);
            IUnitOfWork uow = new UnitOfWork(context);

            // Define repository for Project
            Repository<Project> projectRepository = new Repository<Project>(uow);

            oldCount = projectRepository.GetCount();
            projectRepository.DeleteByFilter(x => x.ProjectId == 26);

            uow.Commit();
            postCommitCount = projectRepository.GetCount();

            // Dispose context
            uow.GetIDbContext().Dispose();

            Console.WriteLine("Delete: old count = {0} | post commit count = {1} ", oldCount, postCommitCount);

            Assert.AreEqual(oldCount - 1, postCommitCount);
        }

        /// <summary>
        /// Test Get All items (IList)
        /// </summary>
        [TestMethod]
        public void GetAllTest()
        {
            int rows = -1;
            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();

            IDbContext context = new DbContextAdap(contextVaffanculo);
            IUnitOfWork uow = new UnitOfWork(context);

            IRepository<Project> projectRepository = new Repository<Project>(uow);
            rows = projectRepository.GetAll().Count;

            // Dispose context
            uow.GetIDbContext().Dispose();

            Console.WriteLine("Total rows: {0}", rows);
            Assert.IsTrue(rows > -1);
                        
        }

        /// <summary>
        /// Test for get IList by filter
        /// </summary>
        [TestMethod]
        public void GetByFilterTest()
        {
            int rows = 0;
            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();
            IDbContext context = new DbContextAdap(contextVaffanculo);

            IUnitOfWork uow = new UnitOfWork(context);

            IRepository<Project> projectRepository =  new Repository<Project>(uow);

            rows = projectRepository.GetByFilter(x => x.Code == "x1" ).Count();

            // Dispose context
            uow.GetIDbContext().Dispose();

            Console.WriteLine("There are \"{0}\" rows with text \"{1}\"", rows, "name");

            Assert.IsTrue(rows > 0 );
        }

        /// <summary>
        /// Test AsQueryable
        /// </summary>
        [TestMethod]
        public void AsQueryableTest()
        {
            int rows = -1;
            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();
            IDbContext context = new DbContextAdap(contextVaffanculo);

            IUnitOfWork uow = new UnitOfWork(context);

            IRepository<Project> projectRepository =  new Repository<Project>(uow);
            var query = projectRepository.AsQueryable();
            var queryFilter = query.Where(x => x.Name == "name");
            rows = queryFilter.Count();

            // Dispose context
            uow.GetIDbContext().Dispose();

            Console.WriteLine("Total rows = {0}", rows);

            Assert.IsTrue(rows > 0);
        }

        /// <summary>
        /// Test for AsQueryableByFilter
        /// </summary>
        [TestMethod]
        public void AsQueryableByFilterTest()
        {
            int rows = -1;
            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();
            IDbContext context = new DbContextAdap(contextVaffanculo);

            IUnitOfWork uow = new UnitOfWork(context);

            IRepository<Project> projectRepository = new Repository<Project>(uow);
            var query = projectRepository.AsQueryableByFilter(x=> x.Name == "name");
            var queryMoreFilter = query.Where(x=> x.Description == "description");
            rows = queryMoreFilter.Count();

            // Dispose context
            uow.GetIDbContext().Dispose();

            Console.WriteLine("Total rows = {0}", rows);

            Assert.IsTrue(rows > 0);
        }

        /// <summary>
        /// Test for GetAllIEnumerable
        /// </summary>
        [TestMethod]
        public void GetAllIEnumerableTest()
        {
            int rows = -1;
            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();
            IDbContext context = new DbContextAdap(contextVaffanculo);

            IUnitOfWork uow = new UnitOfWork(context);

            IRepository<Project> projectRepository = new Repository<Project>(uow);
            var query = projectRepository.GetAllIEnumerable();
            var queryMoreFilter = query.Where(x => x.Description == "description");
            rows = queryMoreFilter.Count();

            // Dispose context
            uow.GetIDbContext().Dispose();

            Console.WriteLine("Total rows = {0}", rows);

            Assert.IsTrue(rows > 0);
        }

        /// <summary>
        /// Test GetIEnumerableByFilter
        /// </summary>
        [TestMethod]
        public void GetIEnumerableByFilterTest()
        {
            int rows = -1;
            // Object context definition to specific model/database
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();
            IDbContext context = new DbContextAdap(contextVaffanculo);

            IUnitOfWork uow = new UnitOfWork(context);

            IRepository<Project> projectRepository = new Repository<Project>(uow);
            var query = projectRepository.GetIEnumerableByFilter(x => x.Name == "name");
            var queryMoreFilter = query.Where(x => x.Code == "x1");

            rows = queryMoreFilter.Count();

            // Dispose resource contex
            uow.GetIDbContext().Dispose();

            Console.WriteLine("Total rows = {0}", rows);

            Assert.IsTrue(rows > 0);
        }

        /// <summary>
        /// Test GetSingle
        /// </summary>
        [TestMethod]
        public void GetSingleTest()
        {
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();
            IDbContext context = new DbContextAdap(contextVaffanculo);

            IUnitOfWork uow = new UnitOfWork(context);

            IRepository<Project> projectRepository = new Repository<Project>(uow);
            Project project = null;

            project = projectRepository.GetSingle(x => x.ProjectId == 23);

            uow.GetIDbContext().Dispose();

            if (project != null)
            {
                Console.WriteLine("id = {0} code = {1}  name = {2}", project.ProjectId, project.Code, project.Name);
            }
            Assert.IsNotNull(project);
        }

        /// <summary>
        /// Test GetFirst
        /// </summary>
        [TestMethod]
        public void GetFirstTest()
        {
            DbContextVaffanculoTest contextVaffanculo = new DbContextVaffanculoTest();
            IDbContext context = new DbContextAdap(contextVaffanculo);

            IUnitOfWork uow = new UnitOfWork(context);

            IRepository<Project> projectRepository = new Repository<Project>(uow);
            Project project = null;

            project = projectRepository.GetFirst(x => x.Name == "name");

            uow.GetIDbContext().Dispose();

            if (project != null)
            {
                Console.WriteLine("id = {0} code = {1}  name = {2}", project.ProjectId, project.Code, project.Name);
            }
            Assert.IsNotNull(project);
        }

    }// End Test Class
}
